package com.example.wenmini.service;

import com.example.wenmini.entity.QuestionnaireFillRequest;
import com.example.wenmini.service.QsFill.QuestionChoice;
import com.example.wenmini.service.QsFill.Submit;
import jakarta.annotation.PreDestroy;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.*;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.*;
import org.openqa.selenium.WebDriver;

@Service
@Slf4j
public class FillService {
    private static final int WAIT_TIMEOUT = 10;
    private static final Random random = new Random();
    private final Map<Long, WebDriverInstance> taskDrivers = new ConcurrentHashMap<>();
    private final Map<Long, Future<?>> taskFutures = new ConcurrentHashMap<>();

    @Autowired
    private ThreadPoolTaskExecutor fillExecutor;

    @Autowired
    private DriverService driverService;

    @Autowired
    private QuestionChoice questionChoice;

    @Autowired
    private Submit submit;

    private record WebDriverInstance(WebDriver driver) { }


    @PreDestroy
    private void cleanupDrivers() {
        taskDrivers.values().forEach(instance -> {
            try {
                instance.driver().quit();
            } catch (Exception e) {
                log.error("关闭浏览器实例失败", e);
            }
        });
        taskDrivers.clear();
    }

    private WebDriver createWebDriver(boolean useProxy) {
        try {
            log.info("开始创建WebDriver...");
            return driverService.createWebDriver(useProxy);
        } catch (Exception e) {
            log.error("创建WebDriver失败：{}", e.getMessage());
            return null;
        }
    }



    @Async("fillExecutor")
    public void createFillTask(QuestionnaireFillRequest request) {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 执行实际的填写任务
                for (int i = 0; i < request.getCount(); i++) {
                    // 检查中断
                    if (Thread.currentThread().isInterrupted()) {
                        return false;
                    }
                    // 执行单次填写
                    fillSingleQuestionnaire(request, i + 1);
                    log.info("第 {} 份问卷填写完成", i + 1);
                    log.info("当前进度：{}/{}", i + 1, request.getCount());
                }
                return true;

            } catch (Exception e) {
                try {
                    throw e;
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            } finally {
                cleanupResources(request.getId());
            }
        }, fillExecutor);

        // 存储任务引用
        taskFutures.put(request.getId(), future);
    }

    private void cleanupResources(Long taskId) {
        WebDriverInstance driverInstance = taskDrivers.remove(taskId);
        if (driverInstance != null) {
            try {
                driverInstance.driver().quit();
            } catch (Exception e) {
                log.error("关闭WebDriver失败：", e);
            }
        }
    }

    private void fillSingleQuestionnaire(QuestionnaireFillRequest task, int index) throws InterruptedException {
        WebDriver driver;
        WebDriverInstance driverInstance = null;
        boolean isTaskPaused = false;

        try {
            long allStartTime = System.currentTimeMillis();

            driver = createWebDriver(task.getUseProxy());
            driverInstance = new WebDriverInstance(driver);
            taskDrivers.put(task.getId(), driverInstance);

            // 访问问卷页面
            if (driver != null) {
                driver.get(task.getUrl());
            }

            // 等待页面加载完成
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(WAIT_TIMEOUT));
            wait.until(webDriver -> Objects.equals(((JavascriptExecutor) webDriver)
                    .executeScript("return document.readyState"), "complete"));

            // 填写问卷
            fillQuestionnaireForm(driver, task.getQuestionConfigs(), task.getId());

            // 尝试提交问卷
            boolean submitted = submit.submitQuestionnaireWithRetry(driver, task.getId());
            if (!submitted) {
                log.error("提交失败，任务ID：{}", task.getId());
                return;
            }

            // 记录总耗时
            long allWaitTime = System.currentTimeMillis();
            log.info("任务完成，总耗时：{} 毫秒", allWaitTime - allStartTime);


            // 如果任务已被暂停，在完成当前填写后清理资源并退出
            if (isTaskPaused) {
                log.info("任务{}当前问卷已完成填写，准备清理资源并停止执行", task.getId());
                cleanupAndExit(task.getId());
                throw new InterruptedException("Task paused after completing current questionnaire");
            }

        } catch (InterruptedException e) {
            log.info("任务{}被中断", task.getId());
            if (isTaskPaused) {
                cleanupAndExit(task.getId());
            }
            throw e;
        } catch (Exception e) {
            // 如果是暂停状态，不将状态更新为失败
            if (!isTaskPaused) {
                log.error("填写问卷失败，任务ID：{}，第{}份，错误：{}", task.getId(), index, e.getMessage());
            } else {
                cleanupAndExit(task.getId());
            }
            throw e;
        } finally {
            // 清理浏览器实例
            if (driverInstance != null) {
                try {
                    driverInstance.driver().quit();
                } catch (Exception e) {
                    log.error("关闭浏览器实例失败", e);
                }
            }
            taskDrivers.remove(task.getId());
        }
    }

    /**
     * 清理资源并结束任务
     */
    private void cleanupAndExit(Long taskId) {
        try {
            log.info("开始清理任务{}的资源", taskId);

            // 清理浏览器实例
            WebDriverInstance driverInstance = taskDrivers.remove(taskId);
            if (driverInstance != null) {
                try {
                    driverInstance.driver().quit();
                } catch (Exception e) {
                    log.error("关闭WebDriver失败：", e);
                }
            }

            // 移除任务Future
            taskFutures.remove(taskId);


            log.info("任务{}的资源清理完成", taskId);
        } catch (Exception e) {
            log.error("清理任务{}资源时发生错误：{}", taskId, e.getMessage());
        }
    }

    // 修改fillQuestionnaireForm方法签名，添加taskId参数
    private void fillQuestionnaireForm(WebDriver driver, List<QuestionnaireFillRequest.QuestionConfigDto> configs, Long taskId) {
        try {
            log.info("开始填写问卷表单...");
            // 等待问题加载
            log.info("等待问题元素加载...");
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(WAIT_TIMEOUT));
            try {
                wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(
                        By.cssSelector(".field-label, .question-title, .title")));
                log.info("问题元素加载完成");
            } catch (TimeoutException e) {
                log.error("等待问题元素超时，当前页面URL：{}", driver.getCurrentUrl());
                log.error("当前页面源码：{}", driver.getPageSource());
                throw new RuntimeException("等待问题元素超时", e);

            }

            log.info("开始查找问题元素...");
            List<WebElement> questions = driver.findElements(
                    By.cssSelector(".field-label, .question-title, .title"));
            log.info("找到 {} 个问题元素", questions.size());

            if (questions.isEmpty()) {
                log.error("未找到任何问题元素，当前页面URL：{}", driver.getCurrentUrl());
                log.error("当前页面源码：{}", driver.getPageSource());
                throw new RuntimeException("未找到任何问题元素");
            }

            // 随机初始等待
            log.info("执行随机初始等待...");
            Thread.sleep(generateRandomDelay(0.3, 0.8));

            log.info("开始处理每个问题，配置数量：{}", configs.size());
            for (int i = 0; i < Math.min(questions.size(), configs.size()); i++) {
                log.info("处理第 {} 个问题", i + 1);
                long startTime = System.currentTimeMillis();
                try {
                    WebElement question = questions.get(i);
                    if (!question.isDisplayed()) {
                        log.warn("第 {} 个问题元素不可见，尝试滚动到可见位置", i + 1);
                        ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", question);
                        Thread.sleep(500);
                    }
                    processQuestion(driver, question, configs.get(i), taskId);
                    long endTime = System.currentTimeMillis();
                    log.info("第 {} 个问题处理完成，耗时：{}ms", i + 1, endTime - startTime);
                } catch (Exception e) {
                    log.error("处理第 {} 个问题时出错：{}", i + 1, e.getMessage());
                    throw e;
                }
            }


        } catch (InterruptedException e) {
            log.error("填写问卷表单被中断：", e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("填写问卷表单被中断", e);
        } catch (Exception e) {
            throw new RuntimeException("填写问卷表单失败：" + e.getMessage());
        }
    }

    // 修改processQuestion方法签名
    private void processQuestion(WebDriver driver, WebElement question,
                                 QuestionnaireFillRequest.QuestionConfigDto config, Long taskId) {
        try {
            log.info("开始处理问题，类型：{}", config.getType());

            // 确保问题元素仍然有效
            try {
                question.isDisplayed();
            } catch (StaleElementReferenceException e) {
                log.error("问题元素已失效，尝试重新查找...");
                // 重新查找元素
                List<WebElement> questions = driver.findElements(
                        By.cssSelector(".field-label, .question-title, .title"));
                question = questions.stream()
                        .filter(q -> {
                            try {
                                return q.isDisplayed();
                            } catch (Exception ex) {
                                return false;
                            }
                        })
                        .findFirst()
                        .orElseThrow(() -> new RuntimeException("无法找到有效的问题元素"));
            }

            log.info("查找问题的父元素...");
            WebElement fieldElement = question.findElement(
                    By.xpath("./ancestor::div[contains(@class, 'field')]"));

            // 处理问题
            switch (config.getType()) {
                case SINGLE_CHOICE:
                    log.info("处理单选题");
                    questionChoice.handleSingleChoice(fieldElement, config, taskId);
                    break;
                case MULTIPLE_CHOICE:
                    log.info("处理多选题");
                    questionChoice.handleMultipleChoice(fieldElement, config, taskId);
                    break;
                case TEXT:
                    log.info("处理文本题");
                    questionChoice.handleTextQuestion(driver,question, config, taskId);
                    break;
                default:
                    log.warn("不支持的问题类型：{}", config.getType());
            }

            // 添加随机思考时间
            log.info("添加随机思考时间...");
            long startTime = System.currentTimeMillis();
            Thread.sleep(generateRandomThinkingTime());
            long endTime = System.currentTimeMillis();
            log.info("随机思考完成，耗时：{}ms", endTime - startTime);

        } catch (InterruptedException e) {
            log.error("处理问题被中断：", e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("处理问题被中断", e);
        } catch (Exception e) {
            throw e;
        }
    }

    private long generateRandomDelay(double minSeconds, double maxSeconds) {
        // 将秒转换为毫秒
        long minMs = (long)(minSeconds * 1000);
        long maxMs = (long)(maxSeconds * 1000);
        return minMs + random.nextInt((int)(maxMs - minMs));
    }




    // 生成随机思考时间
    private long generateRandomThinkingTime() {
        return random.nextInt(200) + 100; // 返回0.1-0.3秒的随机时间
    }

}
